/**
 * Parse the time to string
 * @param {(Object|string|number)} time
 * @param {string} cFormat
 * @returns {string}
 */
import typeOfUtils from './type-of-utils'
import * as __scssFunctions__ from '../style/global.module.scss'

export let scssFunctions = __scssFunctions__.default ? __scssFunctions__.default : __scssFunctions__

export function px2Rem(px: number): string {
  // @ts-ignore
  return px / scssFunctions.baseRem + 'rem'
}


export function isWeiXin() {
  return /MicroMessenger/i.test(window.navigator.userAgent);
}

/**
 * 把url后面的参数格式化成一个对象
 * @param {string} url
 */
export function getQueryObject(url?: string): any {
  url = url == null ? window.location.href : url
  const search = url.substring(url.lastIndexOf('?') + 1)
  const obj = {}
  const reg = /([^?&=]+)=([^?&=]*)/g
  search.replace(reg, (rs, $1, $2) => {
    const name = decodeURIComponent($1)
    let val = decodeURIComponent($2)
    val = String(val)
    obj[name] = val
    return rs
  })
  return obj
}

/**
 * @param {string} str value
 * @returns {number} output value
 */
export function byteLength(str) {
  let s = str.length
  for (let i = str.length - 1; i >= 0; i--) {
    const code = str.charCodeAt(i)
    if (code > 0x7f && code <= 0x7ff) s++
    else if (code > 0x7ff && code <= 0xffff) s += 2
    if (code >= 0xDC00 && code <= 0xDFFF) i--
  }
  return s
}

/**
 * @param {Array} actual
 * @returns {Array}
 */
export function cleanArray(actual = []) {
  const newArray = []
  for (let i = 0; i < actual.length; i++) {
    if (actual[i]) {
      newArray.push(actual[i])
    }
  }
  return newArray
}

/**
 * @param {Object} json
 * @returns {Array}
 */
export function obj2param(json) {
  if (!json) return ''
  return cleanArray(
    // @ts-ignore
    Object.keys(json).map(key => {
      if (json[key] === undefined) return ''
      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
    })
  ).join('&')
}

export function obj2FormData(data) {
  const form = new FormData()
  Object.keys(data).forEach(key => {
    form.append(key, data[key])
  })
  return form
}

/**
 * @param {string} val
 * @returns {string}
 */
export function html2Text(val) {
  const div = document.createElement('div')
  div.innerHTML = val
  return div.textContent || div.innerText
}

/**
 * Merges two objects, giving the last one precedence
 * @param {Object} target
 * @param {(Object|Array)} source
 * @returns {Object}
 */
export function objectMerge(target, source) {
  if (typeof target !== 'object') {
    target = {}
  }
  if (Array.isArray(source)) {
    return source.slice()
  }
  Object.keys(source).forEach(property => {
    const sourceProperty = source[property]
    if (typeof sourceProperty === 'object') {
      target[property] = objectMerge(target[property], sourceProperty)
    } else {
      target[property] = sourceProperty
    }
  })
  return target
}

/**
 * @param {HTMLElement} element
 * @param {string} className
 */
export function toggleClass(element, className) {
  if (!element || !className) {
    return
  }
  let classString = element.className
  const nameIndex = classString.indexOf(className)
  if (nameIndex === -1) {
    classString += '' + className
  } else {
    classString =
      classString.substr(0, nameIndex) +
      classString.substr(nameIndex + className.length)
  }
  element.className = classString
}

/**
 * @param {string} type
 * @returns {Date}
 */
export function getTime(type) {
  if (type === 'start') {
    return new Date().getTime() - 3600 * 1000 * 24 * 90
  } else {
    return new Date(new Date().toDateString())
  }
}

/**
 * @param {Function} func
 * @param {number} wait
 * @param {boolean} immediate
 * @return {*}
 */
export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function () {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function (...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在，重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      // @ts-ignore
      context = args = null
    }

    return result
  }
}

export function debounce4(fn, wait, immediate) {
  let timer
  return function () {
    if (timer) clearTimeout(timer)
    if (immediate) {
      // 如果已经执行过，不再执行
      const callNow = !timer
      timer = setTimeout(() => {
        timer = null
      }, wait)
      if (callNow) {
        fn.apply(this, arguments)
      }
    } else {
      timer = setTimeout(() => {
        fn.apply(this, arguments)
      }, wait)
    }
  }
}

/**
 * @param fn
 * @param wait
 * @param maxTimeLong
 * @returns {function(...[*]=)}
 */
export function throttling(fn, wait, maxTimeLong) {
  let timeout = null
  // @ts-ignore
  let startTime = Date.parse(new Date())
  return function (...args) {
    if (timeout !== null) clearTimeout(timeout)
    // @ts-ignore
    const curTime = Date.parse(new Date())
    if (curTime - startTime >= maxTimeLong) {
      fn(...args)
      startTime = curTime
    } else {
      // @ts-ignore
      timeout = setTimeout(() => {
        fn(...args)
      }, wait)
    }
  }
}

// 节流函数
export function throttle(fn, wait) {
  let last, timer
  const interval = wait || 200
  return function () {
    const th = this
    const args = arguments
    const now = +new Date()
    if (now - last < interval) {
      clearTimeout(timer)
      timer = setTimeout(function () {
        last = now
        fn.apply(th, args)
      }, interval)
    } else {
      last = now
      fn.apply(th, args)
    }
  }
}

/**
 * This is just a simple version of deep copy
 * Has a lot of edge cases bug
 * If you want to use a perfect deep copy, use lodash's _.cloneDeep
 */
export function deepClone<T>(source: T): T {
  if (!source && typeof source !== 'object') {
    throw new Error('error arguments deepClone')
  }
  // @ts-ignore
  const targetObj = source.constructor === Array ? [] : {}
  // @ts-ignore
  Object.keys(source).forEach(keys => {
    // @ts-ignore
    if (source[keys] && typeof source[keys] === 'object') {
      // @ts-ignore
      targetObj[keys] = deepClone(source[keys])
    } else {
      // @ts-ignore
      targetObj[keys] = source[keys]
    }
  })
  // @ts-ignore
  return targetObj
}

/**
 * @param {Array} arr
 * @returns {Array}
 */
export function uniqueArr(arr) {
  return Array.from(new Set(arr))
}

/**
 * @returns {string}
 */
export function createUniqueString() {
  const timestamp = +new Date() + ''
  const randomNum = parseInt(String((1 + Math.random()) * 65536)) + ''
  return (+(randomNum + timestamp)).toString(32)
}

export function computeSum() {
  let sum = 0
  for (let i = 0; i < arguments.length; i++) {
    arguments[i] = Number(arguments[i])
    if (!isNaN(arguments[i])) {
      sum += arguments[i]
    }
  }
  return sum
}

/**
 * 数字转中文
 * @param num
 * @returns {string}
 */
export function convertToChinaNum(num) {
  const arr1 = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
  const arr2 = ['', '十', '百', '千', '万', '十', '百', '千', '亿', '十', '百', '千', '万', '十', '百', '千', '亿'];//可继续追加更高位转换值
  if (!num || isNaN(num)) {
    return "零";
  }
  const english = num.toString().split("");
  let result = "";
  for (let i = 0; i < english.length; i++) {
    const des_i = english.length - 1 - i;//倒序排列设值
    result = arr2[i] + result;
    const arr1_index = english[des_i];
    result = arr1[arr1_index] + result;
  }
  //将【零千、零百】换成【零】 【十零】换成【十】
  result = result.replace(/零(千|百|十)/g, '零').replace(/十零/g, '十');
  //合并中间多个零为一个零
  result = result.replace(/零+/g, '零');
  //将【零亿】换成【亿】【零万】换成【万】
  result = result.replace(/零亿/g, '亿').replace(/零万/g, '万');
  //将【亿万】换成【亿】
  result = result.replace(/亿万/g, '亿');
  //移除末尾的零
  result = result.replace(/零+$/, '')
  //将【零一十】换成【零十】
  //result = result.replace(/零一十/g, '零十');
  //貌似正规读法是零一十
  //将【一十】换成【十】
  result = result.replace(/^一十/g, '十');
  return result;
}

/**
 * 转为大写金额
 * https://gitee.com/cnwhy/nzh?_from=gitee_search
 * @param n
 * @returns {string}
 */
export function convertToBigChinaNum(n) {
  if (!/^(0|[1-9]\d*)(\.\d+)?$/.test(n)) {
    return "数据非法";  //判断数据是否大于0
  }
  let unit = "千百拾亿千百拾万千百拾元角分", str = "";
  n += "00";
  const indexpoint = n.indexOf('.');
  // 如果是小数，截取小数点前面的位数
  if (indexpoint >= 0) {
    // 若为小数，截取需要使用的unit单位
    n = n.substring(0, indexpoint) + n.substr(indexpoint + 1, 2);
  }
  // 若为整数，截取需要使用的unit单位
  unit = unit.substr(unit.length - n.length);
  for (let i = 0; i < n.length; i++) {
    //遍历转化为大写的数字
    str += "零壹贰叁肆伍陆柒捌玖".charAt(n.charAt(i)) + unit.charAt(i);
  }
  // 替换掉数字里面的零字符，得到结果
  return str.replace(/零(千|百|拾|角)/g, "零").replace(/(零)+/g, "零").replace(/零(万|亿|元)/g, "$1").replace(/(亿)万|壹(拾)/g, "$1$2").replace(/^元零?|零分/g, "").replace(/元$/g, "元整");
}

/**
 * @description: 将多个函数转换为链式，通过next确定要不要执行下一个CallBack
 * @param {Function} fns 函数列表
 * @param {Number} calledIndex 从第几个函数开始
 * @return {*}
 */
export function chainCallBacks(fns, calledIndex = 0) {
  const next = () => {
    const fn = fns[calledIndex++]
    calledIndex === fns.length ? fn() : fn(next)
  }
  next()
}

/**
 * 合并数组对象属性
 * @param target
 * @param source
 * @param predicate
 * @param ignoreFiles
 * @param ignoreNull
 * @returns {*[]}
 */
export function arrayMerge(target = [], source = [], predicate, {ignoreFiles = [], ignoreNull = true}) {
  if (!predicate) return target
  if (typeof predicate !== 'function') {
    console.warn('计算列合计【predicate】为一个函数')
    return target
  }
  return target.map(i => {
    const obj = source.find(j => predicate(i, j))
    if (obj) {
      // @ts-ignore
      Object.keys(obj).filter(k => !ignoreFiles.includes(k)).forEach(k => {
        if (ignoreNull) {
          if (ignoreNull && obj[k] !== '' && obj[k] !== null && obj[k] !== undefined && !isNaN(obj[k])) {
            i[k] = obj[k]
          }
        } else {
          i[k] = obj[k]
        }
      })
    }
    return i
  })
}

/**
 * 四舍五入
 * @param val
 * @return {string|number}
 */
export function mathRound(val = 0) {
  if (typeOfUtils.isEmpty(val)) {
    return 0
  }
  return Math.round((val))
}

/**
 * 查找两个字符串中最长的公共子串
 * @param str1 {string}
 * @param str2 {string}
 * @returns {string}
 */
export const findMaxCommonStr = (str1, str2) => {
  //创建一个二维数组
  let temp: any[][] = []
  let max = 0
  let index!: number
  for (let i = 0; i < str1.length; i++) {
    //初始化为二维数组
    temp[i] = []
    for (let j = 0; j < str2.length; j++) {
      //比较两个位置是否相等，相等就将让temp[i][j]相对于temp[i-1][j-1]加一（前提是temp[i-1][j-1]存在）
      if (str1.charAt(i) === str2.charAt(j)) {
        if (i > 0 && j > 0 && temp[i - 1][j - 1] > 0) {
          temp[i][j] = 1 + temp[i - 1][j - 1]
        } else {
          temp[i][j] = 1
        }
        //保存当前temp中最大的数字，并
        if (max < temp[i][j]) {
          max = temp[i][j]
          index = i
        }
      } else {
        temp[i][j] = 0
      }
    }
  }
  return str1.substr(index - max + 1, max)
}

/**
 * 对数字实现千分位格式化处理
 * @param s
 * @param n
 * @returns {string}
 */
export function addThousandsToNumbers(s, n) {
  if (typeOfUtils.isEmpty(s) || typeOfUtils.isEmpty(Number(s))) {
    return s
  }
  if (n) {
    s = parseFloat((s + "").replace(/[^\d\.-]/g, "")).toFixed(n) + ""
  } else {
    s = parseFloat((s + "").replace(/[^\d\.-]/g, "")) + ""
  }
  const l = s.split(".")[0].split("").reverse(),
    r = s.split(".")[1];
  let t;
  t = "";
  for (let i = 0; i < l.length; i++) {
    t += l[i] + ((i + 1) % 3 === 0 && (i + 1) !== l.length ? "," : "");
  }
  if (r) {
    return t.split("").reverse().join("") + "." + r || '';
  } else {
    return t.split("").reverse().join("")
  }
}

/**
 * 去掉千分位格式化处理
 * @param s
 * @returns {number}
 */
export function rAddThousandsToNumbers(s) {
  return parseFloat(s.replace(/[^\d\.-]/g, ""))
}

/**
 * 字符串复制几次
 * @param str
 * @param count
 * @returns {string}
 */
export function strCopyCount(str = '', count = 0) {
  let result = '';
  for (let i = 0; i < count; i++) {
    result += str
  }
  return result
}


/**
 * 获取值 相当于一个链式操作
 * @param obj
 * @param key
 * @return {null|*}
 */
export function getValueFromObj(obj: any, key: string = '') {
  if (!key || key.length === 0) {
    return null
  }
  key = key.replace(/\[([\S\s]+?)]/g, '.$1')
  const fields = key.split('.')
  let result = obj
  for (let i = 0; i < fields.length; i++) {
    key = fields[i]
    result = result[key]
    if (!result) {
      return result
    }
  }
  return result
}

/**
 * 获取浏览器缩放，这个可以处理
 * https://blog.csdn.net/qq_43651168/article/details/131221590
 * 当浏览器缩放时，scrollTop不生效
 */
export function getBrowserZoom() {
  let ratio = 0,
    screen = window.screen,
    ua = navigator.userAgent.toLowerCase();

  if (window.devicePixelRatio !== undefined) {
    ratio = window.devicePixelRatio;
  } else if (~ua.indexOf('msie')) {
    // @ts-ignore
    if (screen.deviceXDPI && screen.logicalXDPI) {
      // @ts-ignore
      ratio = screen.deviceXDPI / screen.logicalXDPI;
    }
  } else if (window.outerWidth !== undefined && window.innerWidth !== undefined) {
    ratio = window.outerWidth / window.innerWidth;
  }
  return ratio;
}

/**
 * 封装requestAnimationFrame
 * 控制速度模拟setinterval
 * @param fn
 * @param delay
 */
export function requestInterval(fn, delay) {
  let requestAnimFrame = (function () {
      return (
        window.requestAnimationFrame ||
        function (callback, element) {
          window.setTimeout(callback, 1000 / 60);
        }
      );
    })(),
    start = new Date().getTime(),
    handle = {
      value: -1
    };

  function loop(timeSpan) {
    handle.value = requestAnimFrame(loop);
    const current = new Date().getTime(),
      delta = current - start;
    if (delta >= delay) {
      fn.call(this, timeSpan);
      start = new Date().getTime();
    }
  }

  handle.value = requestAnimFrame(loop);
  return handle;
}

/**
 * 清除
 * @param handle
 */
export function clearRequestInterval(handle) {
  window.cancelAnimationFrame
    ? window.cancelAnimationFrame(handle.value)
    // @ts-ignore
    : window.webkitCancelAnimationFrame
      // @ts-ignore
      ? window.webkitCancelAnimationFrame(handle.value)
      // @ts-ignore
      : window.webkitCancelRequestAnimationFrame
        // @ts-ignore
        ? window.webkitCancelRequestAnimationFrame(
          handle.value
        ) /* Support for legacy API */
        // @ts-ignore
        : window.mozCancelRequestAnimationFrame
          // @ts-ignore
          ? window.mozCancelRequestAnimationFrame(handle.value)
          // @ts-ignore
          : window.oCancelRequestAnimationFrame
            // @ts-ignore
            ? window.oCancelRequestAnimationFrame(handle.value)
            // @ts-ignore
            : window.msCancelRequestAnimationFrame
              // @ts-ignore
              ? window.msCancelRequestAnimationFrame(handle.value)
              : clearInterval(handle);
}
